package com.itzhoun.util;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 周楠
 * @Date 2022/07/06/下午 11:08
 */
@Component
@Slf4j
public class EsTemplate {

    @Resource
    private RestHighLevelClient restHighLevelClient;

    /**
     * 新增es
     * @param json 内容
     * @param index 索引
     * @param type 类型
     * @param id 主键 可选
     * @return
     */
    public Boolean save(String json, String index, String type, String id){
        // 3.创建请求对象,指定索引库、类型、id(可选)
        IndexRequest indexRequest = new IndexRequest(index, type, id);

        // 4.调用source方法将请求数据封装到IndexRequest请求对象中
        indexRequest.source(json, XContentType.JSON);

        try {
            // 5.调用方法进行数据通信
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            // 6.解析输出结果
            log.info("结果：" + JSON.toJSONString(indexResponse));
            return true;
        } catch (IOException e) {
            log.error("ES报错信息:" + e.getMessage());
        }
        return false;
    }

    /**
     * 获取es值通过条件
     * @param index
     * @param type
     * @param id 可选
     * @return
     */
    public String getEsById(String index, String type, String id){
        // 1.构建GetRequest请求对象,指定索引库、类型、id
        GetRequest getRequest = new GetRequest(index, type, id);

        try {
            // 2.调用方法进行数据通信
            GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
            // 3.解析输出结果
            log.info("结果：" + JSON.toJSONString(getResponse));
            return JSON.toJSONString(getResponse);
        } catch (IOException e) {
            log.error("获取es信息报错:"+ e.getMessage());
        }
        return null;
    }

    /**
     * 修改索引
     * @param json 内容
     * @param index
     * @param type
     * @param id
     * @return
     */
    public boolean updateEsById(String json, String index, String type, String id){
        // 1.构建修改请求对象,指定索引库、类型、id
        UpdateRequest updateRequest = new UpdateRequest("bntang", "product", "1");

        // 2.将需要修改的Json文档数据封装到UpdateRequest请求对象中
        updateRequest.doc(json, XContentType.JSON);

        try {
            // 3.调用方法进行数据通信
            UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            // 4.解析输出结果
            log.info("输出结果：" + JSON.toJSONString(updateResponse));
            return true;
        } catch (IOException e) {
            log.error("Es更新异常，异常信息；"+e.getMessage());
        }
        return false;
    }

    /**
     * 删除索引
     * @param index
     * @param type
     * @param id
     * @return
     */
    public Boolean delEsById(String index, String type, String id){
        try{
            // 1.构建删除请求对象,指定索引库、类型、id
            DeleteRequest deleteRequest = new DeleteRequest(index, type, id);

            // 2.调用方法进行数据通信
            DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);

            // 3.解析输出结果
            log.info("输出结果：" + JSON.toJSONString(deleteResponse));
            return true;
        }catch (IOException e){
            log.error("异常信息,信息异常:" + e.getMessage());
        }
        return false;
    }

    /**
     * 词匹配搜索
     * @param index
     * @param name
     * @param text
     * @return
     */
    public String matchDoc(String index,String name, String text){
        // 1.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest(index);

        // 2.构建SearchSourceBuilder查询对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 3.构建QueryBuilder对象指定查询方式和查询条件
        QueryBuilder queryBuilder = QueryBuilders.matchQuery(name, text);

        // 4.将QueryBuilder对象设置到SearchSourceBuilder中
        sourceBuilder.query(queryBuilder);

        // 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
        searchRequest.source(sourceBuilder);

        try {
            // 6.调用方法进行数据通信
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 7.解析输出结果
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                log.info("结果{} ", sourceAsString);
                return sourceAsString;
            }
        } catch (IOException e) {
            log.error("异常信息{}", e.getMessage());
        }
        return null;
    }

    /**
     * 匹配所有
     * @param index
     * @return
     */
    public String matchAllDoc(String index){
        // 1.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest(index);

        // 2.构建SearchSourceBuilder查询对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 3.构建QueryBuilder对象指定查询方式和查询条件
        QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();

        // 4.将QueryBuilder对象设置到SearchSourceBuilder中
        sourceBuilder.query(queryBuilder);

        // 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
        searchRequest.source(sourceBuilder);

        try {
            // 6.调用方法进行数据通信
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 7.解析输出结果
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                log.info("结果{}" + sourceAsString);
                return sourceAsString;
            }
        } catch (IOException e) {
            log.error("异常信息{}", e.getMessage());
        }
        return null;
    }

    /**
     * 公共方法查询
     * @param index
     * @param queryBuilder
     * @return
     */
    public List<String> commonSearch(String index, QueryBuilder queryBuilder){
        List<String> stringList = new ArrayList<>();
        // 1.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest(index);

        // 2.构建SearchSourceBuilder查询对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 4.将QueryBuilder对象设置到SearchSourceBuilder中
        sourceBuilder.query(queryBuilder);

        // 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
        searchRequest.source(sourceBuilder);

        try {
            // 6.调用方法进行数据通信
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 7.解析输出结果
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                log.info("结果{}", sourceAsString);
                stringList.add(sourceAsString);
            }
            return stringList;
        } catch (IOException e) {
            log.error("报错日志{}", e.getMessage());
        }
        return null;
    }

    /**
     * source过滤
     * @param index
     * @param queryBuilder
     * @return
     */
    public List<String> commonFetchSourceSearch(String index, String[] includes, String[] excludes, QueryBuilder queryBuilder){
        List<String> stringList = new ArrayList<>();
        // 1.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest(index);

        // 2.构建SearchSourceBuilder查询对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 4.将QueryBuilder对象设置到SearchSourceBuilder中
        sourceBuilder.query(queryBuilder);

        // 使用fetchSource实现过滤
        sourceBuilder.fetchSource(includes, excludes);

        // 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
        searchRequest.source(sourceBuilder);

        try {
            // 6.调用方法进行数据通信
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 7.解析输出结果
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                log.info("结果{}", sourceAsString);
                stringList.add(sourceAsString);
            }
            return stringList;
        } catch (IOException e) {
            log.error("报错日志{}", e.getMessage());
        }
        return null;
    }

    /**
     * sort排序
     * @param index
     * @param sortMap
     * @param queryBuilder
     * @return
     */
    public List<String> commonSortSearch(String index, Map<String,Object> sortMap, QueryBuilder queryBuilder){
        List<String> stringList = new ArrayList<>();
        // 1.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest(index);

        // 2.构建SearchSourceBuilder查询对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 4.将QueryBuilder对象设置到SearchSourceBuilder中
        sourceBuilder.query(queryBuilder);

        // todo 使用fetchSource实现过滤

        // 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
        searchRequest.source(sourceBuilder);

        try {
            // 6.调用方法进行数据通信
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 7.解析输出结果
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                log.info("结果{}", sourceAsString);
                stringList.add(sourceAsString);
            }
            return stringList;
        } catch (IOException e) {
            log.error("报错日志{}", e.getMessage());
        }
        return null;
    }



}
